/*
 * SPDX-License-Identifier: Apache-2.0
 *
 * The OpenSearch Contributors require contributions made to
 * this file be licensed under the Apache-2.0 license or a
 * compatible open source license.
 */

/*
 * Licensed to Elasticsearch B.V. under one or more contributor
 * license agreements. See the NOTICE file distributed with
 * this work for additional information regarding copyright
 * ownership. Elasticsearch B.V. licenses this file to you under
 * the Apache License, Version 2.0 (the "License"); you may
 * not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

/*
 * Modifications Copyright OpenSearch Contributors. See
 * GitHub history for details.
 */

package org.opensearch.client.opensearch.core.mget;

import jakarta.json.stream.JsonGenerator;
import java.util.List;
import java.util.function.Function;
import javax.annotation.Nullable;
import org.opensearch.client.json.JsonpDeserializable;
import org.opensearch.client.json.JsonpDeserializer;
import org.opensearch.client.json.JsonpMapper;
import org.opensearch.client.json.ObjectBuilderDeserializer;
import org.opensearch.client.json.ObjectDeserializer;
import org.opensearch.client.json.PlainJsonSerializable;
import org.opensearch.client.opensearch._types.VersionType;
import org.opensearch.client.opensearch.core.search.SourceConfig;
import org.opensearch.client.util.ApiTypeHelper;
import org.opensearch.client.util.ObjectBuilder;
import org.opensearch.client.util.ObjectBuilderBase;

// typedef: _global.mget.Operation

@JsonpDeserializable
public class MultiGetOperation implements PlainJsonSerializable {
    private final String id;

    @Nullable
    private final String index;

    @Nullable
    private final String routing;

    @Nullable
    private final SourceConfig source;

    private final List<String> storedFields;

    @Nullable
    private final Long version;

    @Nullable
    private final VersionType versionType;

    // ---------------------------------------------------------------------------------------------

    private MultiGetOperation(Builder builder) {

        this.id = ApiTypeHelper.requireNonNull(builder.id, this, "id");
        this.index = builder.index;
        this.routing = builder.routing;
        this.source = builder.source;
        this.storedFields = ApiTypeHelper.unmodifiable(builder.storedFields);
        this.version = builder.version;
        this.versionType = builder.versionType;

    }

    public static MultiGetOperation of(Function<Builder, ObjectBuilder<MultiGetOperation>> fn) {
        return fn.apply(new Builder()).build();
    }

    /**
     * Required - API name: {@code _id}
     */
    public final String id() {
        return this.id;
    }

    /**
     * API name: {@code _index}
     */
    @Nullable
    public final String index() {
        return this.index;
    }

    /**
     * API name: {@code routing}
     */
    @Nullable
    public final String routing() {
        return this.routing;
    }

    /**
     * API name: {@code _source}
     */
    @Nullable
    public final SourceConfig source() {
        return this.source;
    }

    /**
     * API name: {@code stored_fields}
     */
    public final List<String> storedFields() {
        return this.storedFields;
    }

    /**
     * API name: {@code version}
     */
    @Nullable
    public final Long version() {
        return this.version;
    }

    /**
     * API name: {@code version_type}
     */
    @Nullable
    public final VersionType versionType() {
        return this.versionType;
    }

    /**
     * Serialize this object to JSON.
     */
    public void serialize(JsonGenerator generator, JsonpMapper mapper) {
        generator.writeStartObject();
        serializeInternal(generator, mapper);
        generator.writeEnd();
    }

    protected void serializeInternal(JsonGenerator generator, JsonpMapper mapper) {

        generator.writeKey("_id");
        generator.write(this.id);

        if (this.index != null) {
            generator.writeKey("_index");
            generator.write(this.index);

        }
        if (this.routing != null) {
            generator.writeKey("routing");
            generator.write(this.routing);

        }
        if (this.source != null) {
            generator.writeKey("_source");
            this.source.serialize(generator, mapper);

        }
        if (ApiTypeHelper.isDefined(this.storedFields)) {
            generator.writeKey("stored_fields");
            generator.writeStartArray();
            for (String item0 : this.storedFields) {
                generator.write(item0);

            }
            generator.writeEnd();

        }
        if (this.version != null) {
            generator.writeKey("version");
            generator.write(this.version);

        }
        if (this.versionType != null) {
            generator.writeKey("version_type");
            this.versionType.serialize(generator, mapper);
        }

    }

    // ---------------------------------------------------------------------------------------------

    /**
     * Builder for {@link MultiGetOperation}.
     */

    public static class Builder extends ObjectBuilderBase implements ObjectBuilder<MultiGetOperation> {
        private String id;

        @Nullable
        private String index;

        @Nullable
        private String routing;

        @Nullable
        private SourceConfig source;

        @Nullable
        private List<String> storedFields;

        @Nullable
        private Long version;

        @Nullable
        private VersionType versionType;

        /**
         * Required - API name: {@code _id}
         */
        public final Builder id(String value) {
            this.id = value;
            return this;
        }

        /**
         * API name: {@code _index}
         */
        public final Builder index(@Nullable String value) {
            this.index = value;
            return this;
        }

        /**
         * API name: {@code routing}
         */
        public final Builder routing(@Nullable String value) {
            this.routing = value;
            return this;
        }

        /**
         * API name: {@code _source}
         */
        public final Builder source(@Nullable SourceConfig value) {
            this.source = value;
            return this;
        }

        /**
         * API name: {@code _source}
         */
        public final Builder source(Function<SourceConfig.Builder, ObjectBuilder<SourceConfig>> fn) {
            return this.source(fn.apply(new SourceConfig.Builder()).build());
        }

        /**
         * API name: {@code stored_fields}
         * <p>
         * Adds all elements of <code>list</code> to <code>storedFields</code>.
         */
        public final Builder storedFields(List<String> list) {
            this.storedFields = _listAddAll(this.storedFields, list);
            return this;
        }

        /**
         * API name: {@code stored_fields}
         * <p>
         * Adds one or more values to <code>storedFields</code>.
         */
        public final Builder storedFields(String value, String... values) {
            this.storedFields = _listAdd(this.storedFields, value, values);
            return this;
        }

        /**
         * API name: {@code version}
         */
        public final Builder version(@Nullable Long value) {
            this.version = value;
            return this;
        }

        /**
         * API name: {@code version_type}
         */
        public final Builder versionType(@Nullable VersionType value) {
            this.versionType = value;
            return this;
        }

        /**
         * Builds a {@link MultiGetOperation}.
         *
         * @throws NullPointerException
         *             if some of the required fields are null.
         */
        public MultiGetOperation build() {
            _checkSingleUse();

            return new MultiGetOperation(this);
        }
    }

    // ---------------------------------------------------------------------------------------------

    /**
     * Json deserializer for {@link MultiGetOperation}
     */
    public static final JsonpDeserializer<MultiGetOperation> _DESERIALIZER = ObjectBuilderDeserializer.lazy(
        Builder::new,
        MultiGetOperation::setupMultiGetOperationDeserializer
    );

    protected static void setupMultiGetOperationDeserializer(ObjectDeserializer<MultiGetOperation.Builder> op) {

        op.add(Builder::id, JsonpDeserializer.stringDeserializer(), "_id");
        op.add(Builder::index, JsonpDeserializer.stringDeserializer(), "_index");
        op.add(Builder::routing, JsonpDeserializer.stringDeserializer(), "routing");
        op.add(Builder::source, SourceConfig._DESERIALIZER, "_source");
        op.add(Builder::storedFields, JsonpDeserializer.arrayDeserializer(JsonpDeserializer.stringDeserializer()), "stored_fields");
        op.add(Builder::version, JsonpDeserializer.longDeserializer(), "version");
        op.add(Builder::versionType, VersionType._DESERIALIZER, "version_type");

    }

}
